/**
 * https://www.bilibili.com/video/BV1Mb411e7re?p=27
 * AT24C02 / AT24C02N, 几毛钱1个
 * 是一种可以实现掉电不丢失的存储器，可用于保存单片机运行时想要永久保存的数据信息
 * 存储介质：E2PROM (Electrically Erasable Programmable Read Only Memory)
 * 通讯接口：I2C总线
 * 容量：256字节
 * 
 * https://www.bilibili.com/video/BV1Mb411e7re?p=28
 */
#include <REGX52.H>
#include "Link/Single_Keyboard_Utils.h"
#include "Link/Nixie_Tube_Utils.h"
#include "Link/Timer0_Utils.h"
#include "Link/AT24C02_Utils.h"
#include "Link/UART_Utils.h"

static void Timer0_onTick();
static void Sec_Loop(void);

static unsigned char RunFlag, Min, Sec, MiniSec, i = 0, temp = 99;
static unsigned char NIXIE_DATAS[6];

void main_at24c02_2() {
    unsigned char keyNum;
    UART_Init(0, 4800);
    UART_sendString("AT24C02: Store", 1);
    
    Timer0_Init(1000, 0);
    Timer0_setOnTickListener_Exact(1, &Timer0_onTick);
    while (1) {
        //独立按键
        keyNum = Single_Keyboard_Down_Timer_Get();
        if (keyNum) UART_sendStringFormat(1, "keyNum = %bu", keyNum);
        switch (keyNum) {
            //启动标志位翻转
            case 1: RunFlag = !RunFlag; break;
            //分秒清0
            case 2: Min = Sec = MiniSec = 0; break;
            case 3: 
                //将分秒写入AT24C02
                AT24C02_WriteByte(0, Min, 1);
                AT24C02_WriteByte(1, Sec, 1);
                AT24C02_WriteByte(2, MiniSec, 1);
                UART_sendStringFormat(1, "Write OK: min=%bu,sec=%bu,ms=%bu", Min, Sec, MiniSec);
                break;
            case 4:
                //读出AT24C02数据
                Min = AT24C02_ReadByte(0);
                Sec = AT24C02_ReadByte(1);
                MiniSec = AT24C02_ReadByte(2);
                UART_sendStringFormat(1, "Read OK: min=%bu,sec=%bu,ms=%bu", Min, Sec, MiniSec);
                break;
            default: break;
        }
        //设置显示缓存，显示数据
        NIXIE_DATAS[0] = Min / 10;
        NIXIE_DATAS[1] = Min % 10;
        NIXIE_DATAS[2] = Sec / 10;
        NIXIE_DATAS[3] = Sec % 10;
        NIXIE_DATAS[4] = MiniSec / 10;
        NIXIE_DATAS[5] = MiniSec % 10;
        if (temp != i) {
            //TODO 下面1句一定要放在main()里面, if放在中断里面的话, 按键的时候程序会大概率崩溃, 原因是???
            Nixie_Tube_Light_Num(1, i + 1, NIXIE_DATAS[i], i == 1 || i == 3, 1);
            temp = i;
        }
    }
}

static void Timer0_onTick() {
    static unsigned char T0Count1, T0Count2, T0Count3;
    T0Count1 ++;
    //独立键盘, 每15ms调用1次
    if (T0Count1 >= 15) {
        T0Count1 = 0;
        Single_Keyboard_Down_Timer(1);
    }
    
    //数码管, 每2ms扫描1次
    T0Count2 ++;
    if (T0Count2 >= 2) {
        T0Count2 = 0;
        //TODO 下面这句如果写在这个中断函数中, 按下独立按键1 2 大概率会崩溃, 按下3 4 的时候中概率会崩溃, 要写到main()里面, 啥原因??
        // Nixie_Tube_Light_Num(1, i + 1, NIXIE_DATAS[i], i == 1 || i == 3, 1);
        // UART_sendNum(NIXIE_DATAS[i], 0);
        i++;
        if (i >= 6) i = 0;
    }
    
    // //秒表驱动函数, 10ms调用一次数
    T0Count3++;
    if(T0Count3 >= 10) {
        T0Count3 = 0;
        Sec_Loop();
    }
}

/**
  * @brief  秒表驱动函数，在中断中调用
  * @param  无
  * @retval 无
  */
void Sec_Loop(void) {
    if(RunFlag) {
        MiniSec++;
        if(MiniSec >= 100) {
            MiniSec = 0;
            Sec++;
            if(Sec >= 60) {
                Sec = 0;
                Min++;
                if(Min >= 60) {
                    Min = 0;
                }
            }
        }
    }
}